import {BeatMapParser, NoteEvent, WallEvent} from "./BeatMapParser"
import {findLastElement} from "../../../utils/util"

class NoteEventV3 extends NoteEvent {
  AngleOffset
}

class BeatMapParserV3 extends BeatMapParser{
  bpmEvents = []

  constructor(info, data){
    super(info, data)
    if("bpmEvents" in this.data){
      this.data["bpmEvents"]?.sort((a,b)=> a.b - b.b)

      // Init Bpm Events
      let currentTime = 0;
      let lastBeat = 0;
      let lastBpm = this.info.getRawBpm()
      for(const event of this.data["bpmEvents"]){      
        currentTime += BeatMapParser.RawTimeFromBeat(event.b - lastBeat, lastBpm)
        this.bpmEvents.push({
          "Beat": event.b,
          "BPM": event.m,
          "Time": currentTime
        })
        lastBeat = event.b;
        lastBpm = event.m;
      }
    }
  }

  initNoteEvents(){
    for(let i= 0; i < this.data['colorNotes'].length; i++){
      const rawData = this.data['colorNotes'][i]
      const newEvent = new NoteEventV3()
      Object.assign(newEvent, {
        Index: i,
        Beat: rawData.b,
        LineIndex: rawData.x,
        LineLayer: rawData.y,
        Type: rawData.c,
        CutDirection: rawData.d,
        AngleOffset: rawData.a
      })
      this.noteEvents.push(newEvent)
    }
  }

  initWallEvents(){
    for(let i= 0; i < this.data['obstacles'].length; i++){
      const rawData = this.data['obstacles'][i]

      const newEvent = new WallEvent()
      Object.assign(newEvent, {
        Index: i,
        Beat: rawData['b'],
        LineIndex: rawData['x'],
        LineLayer: rawData['y'],
        Height: rawData['h'],
        Width: rawData['w'],
        Duration: rawData['d']
      })
      this.wallEvents.push(newEvent)
    }
  }

  TimeFromBeat(beat){
    if(!this.bpmEvents || this.bpmEvents.length == 0)
      return super.TimeFromBeat(beat)
    const lastChange = findLastElement(this.bpmEvents, beat, ele=>ele.Beat)
    if(lastChange == null)
      return super.TimeFromBeat(beat)
    return lastChange.Time + BeatMapParser.RawTimeFromBeat(beat - lastChange.Beat, lastChange.BPM)
  }

  BeatFromTime(time){
    if(!this.bpmEvents || this.bpmEvents.length == 0)
      return super.BeatFromTime(time)
    const lastChange = findLastElement(this.bpmEvents, time, ele=>ele.Time)
    if(lastChange == null){
      return super.BeatFromTime(time)
    }
    return lastChange.Beat + BeatMapParser.RawBeatFromTime(time - lastChange.Time, lastChange.BPM)
  }

  getBpmFromBeat(beat){
    const lastChange = findLastElement(this.bpmEvents, beat, ele=>ele.Beat)
    if(lastChange.BPM <= 0)
      return super.getBpmFromBeat(beat);
    return lastChange.BPM
  }
}

export {BeatMapParserV3, NoteEventV3}